package gsw.tool.http.call;

import java.io.IOException;
import java.util.ArrayList;

import gsw.tool.http.HttpClient;
import gsw.tool.http.Response;
import gsw.tool.http.chain.Interceptor;
import gsw.tool.http.chain.InterceptorCallService;
import gsw.tool.http.chain.InterceptorChain;
import gsw.tool.http.chain.InterceptorConnection;
import gsw.tool.http.chain.InterceptorHeaders;
import gsw.tool.http.chain.InterceptorRetry;
import gsw.tool.http.request.Request;

/**
 * 请求任务
 */
public class Call {
    Request request;
    HttpClient client;

    //是否执行过
    boolean executed;
    //是否退出了
    boolean canceled;

    public Call(HttpClient client, Request request) {
        this.client = client;
        this.request = request;
    }

    /**
     * 异步调用
     */
    public Call enqueue(Callback callback) {
        //同一请求执行一次
        synchronized (this) {
            if (executed) {
                throw new IllegalStateException("Already Executed");
            }
            executed = true;
        }
        client.dispatcher().enqueue(new AsyncCall(callback));
        return this;
    }

    public void cancel() {
        canceled = true;
    }

    public boolean isCanceled() {
        return canceled;
    }

    public Request request() {
        return request;
    }

    public HttpClient client() {
        return client;
    }

    Response getResponse() throws IOException {
        ArrayList<Interceptor> interceptors = new ArrayList<>();
        interceptors.addAll(client.interceptors());
        interceptors.add(new InterceptorRetry());
        interceptors.add(new InterceptorHeaders());
        interceptors.add(new InterceptorConnection());
        interceptors.add(new InterceptorCallService());
        InterceptorChain interceptorChain = new InterceptorChain(interceptors, 0, this, null);
        return interceptorChain.proceed();
    }

    /**
     * 异步请求任务
     */
    final class AsyncCall implements Runnable {

        private final Callback callback;

        public AsyncCall(Callback callback) {
            this.callback = callback;
        }

        @Override
        public void run() {
            //是否已经通知过callback
            boolean signalledCallback = false;
            try {
                //获取响应
                Response response = getResponse();
                if (canceled) {
                    signalledCallback = true;
                    callback.onFailure(Call.this, new IOException("Canceled"));
                } else {
                    signalledCallback = true;
                    callback.onResponse(Call.this, response);
                }
            } catch (IOException e) {
                if (!signalledCallback) {
                    callback.onFailure(Call.this, e);
                }
            } finally {
                client.dispatcher().finished(this);
            }
        }

        public String host() {
            return request.url().getHost();
        }
    }


}
